package org.hawk.gwt.ppc.scanner;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.hawk.gwt.ppc.utils.Name;
/**
 * {@link SourcesLoader} that loads the sources from filesystem
 * classpath. Usually you shouldn't use it directly - use 
 * {@link UniversalSourcesLoader} instead.
 * @author alex.bereznevatiy@gmail.com
 */
public class FileSystemSourcesLoader extends AbstractSourcesLoader implements SourcesLoader {
	private File root;
	/**
	 * Creates sources loader for root of the file system.
	 * Passed path should be existent directory.
	 * @param root
	 */
	public FileSystemSourcesLoader(String root){
		this(new File(root));
	}
	/**
	 * Creates sources loader for root of the file system.
	 * Passed path should be existent directory.
	 * @param root
	 */
	public FileSystemSourcesLoader(File root){
		if(!root.exists()){
			throw new IllegalArgumentException(
				root+" is not exists");
		}
		this.root = root;
	}
	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.scanner.SourcesLoader#getClasses(java.lang.String)
	 */
	public List<String> getClasses(String packageName) {
		File pkg = getPackage(packageName);
		if(!pkg.isDirectory()){
			return Collections.emptyList();
		}
		ArrayList<String> result = new ArrayList<String>();
		for(String file : pkg.list()){
			addIfJavaSrc(result,packageName, file);
		}
		Collections.sort(result);
		result.trimToSize();
		return Collections.unmodifiableList(result);
	}
	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.scanner.SourcesLoader#getResource(java.lang.String)
	 */
	public URL getResource(String name) {
		try {
			File file = new File(root,name);
			if(!file.exists()){
				return null;
			}
			return file.toURI().toURL();
		}
		catch(Exception ex){
			return null;
		}
	}
	
	private File getPackage(String packageName) {
		validatePackageName(packageName);
		return new File(root,packageName.replace(
			Name.PACKAGE_SEPARATOR, File.separatorChar));
	}
	
	private void addIfJavaSrc(ArrayList<String> result,String packageName, String name) {
		if(!Name.isJavaSrc(name)){
			return;
		}
		result.add(Name.getChildJavaName(
			packageName,Name.fsToJava(name)));
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.scanner.SourcesLoader#getSubpackages(java.lang.String)
	 */
	public List<String> getSubpackages(String packageName) {
		File pkg = getPackage(packageName);
		if(!pkg.isDirectory()){
			return Collections.emptyList();
		}
		ArrayList<String> result = new ArrayList<String>();
		for(String name : pkg.list()){
			File child = new File(pkg,name);
			if(child.isDirectory()&&Name.isValidPackageName(name)){
				result.add(Name.getChildJavaName(packageName,name));
			}
		}
		result.trimToSize();
		Collections.sort(result);
		return Collections.unmodifiableList(result);
	}
	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.scanner.SourcesLoader#toUrl()
	 */
	public URL toUrl(){
		try {
			return root.toURI().toURL();
		}
		catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}
	
	@Override
	public String toString() {
		return root.getAbsolutePath();
	}
	
	@Override
	public boolean equals(Object obj) {
		if(this==obj)return true;
		if(obj instanceof JarSourcesLoader){
			FileSystemSourcesLoader loader = (FileSystemSourcesLoader)obj;
			return loader.root.equals(root);
		}
		return false;
	}
}
